package com.vay.de.dang.online.view;

import android.content.Context;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;

import java.util.ArrayList;
import java.util.List;

import com.vay.de.dang.online.R;

public class PullRefreshView extends FrameLayout {

    private static final int ViewNone = -1;
    private static final int ViewHeader = 1;
    private static final int ViewContent = 2;
    private static final int ViewFooter = 3;
    private LinearLayoutManager layoutManager;
    private SwipeRefreshLayout swipeRefreshLayout;
    private RecyclerView recyclerView;
    private RecyclerView.Adapter recyclerAdapter;
    private RecyclerAdapter dataAdapter;
    private LayoutInflater inflater;
    private View headerView;
    private View emptyView;
    private boolean enablePull;

    public PullRefreshView(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        View view = LayoutInflater.from(context).inflate(R.layout.pull_refresh_view, null);
        addView(view);

        enablePull = true;
        swipeRefreshLayout = findViewById(R.id.refresh_layout);
        swipeRefreshLayout.setColorSchemeColors(
                ContextCompat.getColor(getContext(), R.color.purple_500)
        );
        recyclerView = findViewById(R.id.recycle_view);
        inflater = LayoutInflater.from(context);

        layoutManager = new LinearLayoutManager(context);
        recyclerView.setLayoutManager(layoutManager);
        swipeRefreshLayout.setOnRefreshListener(() -> {
            if (enablePull) {
                if (dataAdapter != null && dataAdapter.status == 0) {
                    dataAdapter.status = 1;
                    dataAdapter.onReload();
                } else {
                    swipeRefreshLayout.setRefreshing(false);
                }
            } else {
                swipeRefreshLayout.setRefreshing(false);
            }
        });

        recyclerAdapter = new RecyclerView.Adapter() {

            @Override
            public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

                View view = null;

                if (viewType == ViewContent) {
                    if (dataAdapter.getItemLayout() != 0) {
                        view = inflater.inflate(dataAdapter.getItemLayout(), parent, false);
                    }
                } else if (viewType == ViewFooter) {
                    view = inflater.inflate(R.layout.item_more_layout, parent, false);
                } else if (viewType == ViewHeader) {
                    view = headerView;
                }

                return view != null ? new PullRefreshHolder(view) : null;
            }

            @Override
            public int getItemViewType(int position) {
                if (position == 0) {
                    if (headerView != null) return ViewHeader;
                    else if (dataAdapter != null) return ViewContent;
                } else {
                    int size = getItemCount();
                    if (dataAdapter != null) {
                        if (position == size - 1) {
                            return dataAdapter.hasNextPage() ? ViewFooter : ViewContent;
                        } else {
                            return ViewContent;
                        }
                    }
                }

                return ViewNone;
            }

            @Override
            public int getItemCount() {
                int head = headerView != null ? 1 : 0;
                int items = dataAdapter != null ? dataAdapter.getItemCount() : 0;
                if (items > 0 && dataAdapter.hasNextPage()) {
                    return head + items + 1;
                } else {
                    return head + items;
                }
            }

            @Override
            public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
                if (position == 0 && headerView != null) return;
                int newPosition = position - (headerView != null ? 1 : 0);
                if (newPosition < dataAdapter.getItemCount()) {
                    if (holder instanceof PullRefreshHolder && dataAdapter != null) {
                        dataAdapter.onBindViewHolder((PullRefreshHolder) holder, newPosition);
                    }
                }
            }

        };

        recyclerView.setAdapter(recyclerAdapter);
        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {

            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);

                // stop
                if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                    if (dataAdapter != null) dataAdapter.onIdle();
                }
                // dragging
                else if (newState == RecyclerView.SCROLL_STATE_DRAGGING) {
                    if (dataAdapter != null) dataAdapter.onDragging();
                }
            }

            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);

                if (dataAdapter != null) {

                    if (dataAdapter.status == 1 || !dataAdapter.hasNextPage()) return;

                    int lastVisibleItem = layoutManager.findLastVisibleItemPosition();
                    int totalItemCount = layoutManager.getItemCount();

                    if (lastVisibleItem == totalItemCount - 1 && dataAdapter.hasNextPage()) {
                        dataAdapter.loadNextPage();
                        dataAdapter.status = 1;
                    }
                }
            }
        });
    }

    public SwipeRefreshLayout getSwipeRefreshLayout() {
        return swipeRefreshLayout;
    }

    public void setHeaderView(View view) {
        headerView = view;
    }

    public void setRecyclerAdapter(RecyclerAdapter adapter) {
        dataAdapter = adapter;
        if (dataAdapter != null) {
            adapter.loadRecyclerViewAdapter(this);

            // empty view
            if (adapter.getEmptyLayout() != 0) {
                emptyView = inflater.inflate(adapter.getEmptyLayout(), null);
                LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT,
                        LayoutParams.WRAP_CONTENT);
                lp.gravity = Gravity.CENTER;
                addView(emptyView);
                emptyView.setVisibility(View.GONE);
            }
        }
    }

    public void setEnablePullRefresh(boolean enable) {
        enablePull = enable;
    }

    public RecyclerView getRecyclerView() {
        return recyclerView;
    }

    private void checkEmpty() {

        if (emptyView == null) return;

        if (dataAdapter != null && !dataAdapter.isEmpty()) {
            emptyView.setVisibility(View.GONE);
        } else {
            emptyView.setVisibility(View.VISIBLE);
        }
    }

    public static abstract class RecyclerAdapter<T> {

        protected final List<T> mData = new ArrayList<>();
        private PullRefreshView mPullRefreshView;
        private int status;

        public void loadData(List<T> temp, boolean clear) {

            if (clear) {
                clear();
            }

            loadData(temp);
        }

        public void loadData(List<T> temp) {

            if (temp != null) {
                for (T t : temp) {
                    if (!mData.contains(t)) mData.add(t);
                }
            }

            if (mPullRefreshView != null) mPullRefreshView.checkEmpty();
            notifyDataSetChanged();
        }

        public boolean isPullRefreshing() {
            return mPullRefreshView != null && mPullRefreshView.swipeRefreshLayout.isRefreshing();
        }

        public void notifyDataSetChanged() {
            if (mPullRefreshView != null) mPullRefreshView.recyclerAdapter.notifyDataSetChanged();
        }

        public void setRefreshing(boolean refreshing) {
            if (mPullRefreshView != null) {
                mPullRefreshView.swipeRefreshLayout.setRefreshing(refreshing);
            }
        }

        private final void loadRecyclerViewAdapter(PullRefreshView view) {
            mPullRefreshView = view;
        }

        public int getItemCount() {
            return mData.size();
        }

        public void remove(T t) {
            if (t != null) {
                mData.remove(t);
                if (mPullRefreshView != null) {
                    mPullRefreshView.recyclerAdapter.notifyDataSetChanged();
                    mPullRefreshView.checkEmpty();
                }
            }
        }

        public void add(T t) {
            if (t != null) {
                mData.add(t);
                if (mPullRefreshView != null) {
                    mPullRefreshView.recyclerAdapter.notifyDataSetChanged();
                    mPullRefreshView.checkEmpty();
                }
            }
        }

        public void add(T t, int index) {
            if (t != null) {
                mData.add(index, t);
                if (mPullRefreshView != null) {
                    mPullRefreshView.recyclerAdapter.notifyDataSetChanged();
                    mPullRefreshView.checkEmpty();
                }
            }
        }

        public void removeAll(List<T> list) {
            if (list != null && list.size() > 0) {
                mData.removeAll(list);
                notifyDataSetChanged();
            }
        }

        public void onIdle() {

        }

        public void onDragging() {

        }

        public T getItem(int position) {
            return mData.get(position);
        }

        public void resetAll() {
            status = 0;
            if (mPullRefreshView != null)
                mPullRefreshView.swipeRefreshLayout.setRefreshing(false);
        }

        public boolean isEmpty() {
            return mData.isEmpty();
        }

        public void clear() {
            mData.clear();

            if (mPullRefreshView != null) {
                mPullRefreshView.recyclerAdapter.notifyDataSetChanged();
                mPullRefreshView.checkEmpty();
            }
        }

        public void onResume() {

            if (isEmpty()) {
                setRefreshing(true);
                onReload();
                status = 1;
            } else {
                notifyDataSetChanged();
            }
        }

        public abstract int getItemLayout();

        public int getEmptyLayout() {
            return 0;
        }

        public abstract void onReload();

        public abstract boolean hasNextPage();

        public abstract boolean loadNextPage();

        public abstract void onBindViewHolder(PullRefreshHolder holder, int position);
    }
}
